package com.odata.springboot.starter.odata.packagesacn;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 *
 * 包扫描 获取指定包下的全部类的全路径
 *
 * @author : yongxiang
 * @description : 
 * @param
 * @date : 16:01 2021/6/30
*/
@Slf4j
public class ClasspathPackageScanner {

     /**
      *获取指定包下的所有字节码文件的全类名
      */
     public static List<String> getFullyQualifiedClassNameList(String basePackage) throws IOException {
         return doScan(basePackage, new ArrayList<String>());
     }

     /**
      *doScan函数
      * @param basePackage
      * @param nameList
      * @return
      * @throws IOException
      */
     private static List<String> doScan(String basePackage, List<String> nameList) throws IOException {
         String splashPath = StringUtil.dotToSplash(basePackage);

         URL url = ClasspathPackageScanner.class.getClassLoader().getResource(splashPath);
         String filePath = StringUtil.getRootPath(url);
         List<String> names;
         if (isJarFile(filePath)) {

             names = readFromJarFile(filePath, splashPath);
         } else {

             names = readFromDirectory(filePath);
         }
         for (String name : names) {
             if (isClassFile(name)) {
                 log.info("odata entity..." + name);
                 nameList.add(toFullyQualifiedName(name, basePackage));
             } else {
                 doScan(basePackage + "." + name, nameList);
             }
         }
         return nameList;
     }

     private static String toFullyQualifiedName(String shortName, String basePackage) {
         StringBuilder sb = new StringBuilder(basePackage);
         sb.append('.');
         sb.append(StringUtil.trimExtension(shortName));
         return sb.toString();
     }

     private static List<String> readFromJarFile(String jarPath, String splashedPackageName) throws IOException {

         JarInputStream jarIn = new JarInputStream(new FileInputStream(jarPath));
         JarEntry entry = jarIn.getNextJarEntry();
         List<String> nameList = new ArrayList<String>();
         while (null != entry) {
             String name = entry.getName();
             if (name.startsWith(splashedPackageName) && isClassFile(name)) {
                 nameList.add(name);
             }
             entry = jarIn.getNextJarEntry();
         }

         return nameList;
     }

     private static List<String> readFromDirectory(String path) {
         File file = new File(path);
         String[] names = file.list();
         if (null == names) {
             return null;
         }

         return Arrays.asList(names);
     }

     private static boolean isClassFile(String name) {
         return name.endsWith(".class");
     }

     private static boolean isJarFile(String name) {
         return name.endsWith(".jar");
     }

 }